//-------------------------------------------------
// Litchi Game Server Framework
// Copyright(c) 2019 phantaci <phantacix@qq.com>
// MIT Licensed
//-------------------------------------------------
package com.mygame.common.component;


import com.esotericsoftware.reflectasm.MethodAccess;
import com.mygame.common.component.annotation.EventHandler;
import com.mygame.common.component.annotation.Handler;
import com.mygame.common.component.annotation.Route;
import com.mygame.common.component.annotation.Rpc;
import com.mygame.common.component.extend.ASMMethod;
import com.mygame.common.component.utils.StringUtils;
import com.mygame.common.msg.ServiceEnum;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 路由信息
 */
public class RouteInfo {

    /**
     * nodeType.className.MethodName
     */
    public String routeName;

    /**
     * route对象实例
     */
    public BaseRoute instance;

    public Class<?> instanceClazz;

    /**
     * 当前执行逻辑的方法
     */
    public ASMMethod method;

    public Route routeAnnotation;
    public Rpc rpcAnnotation;
    public Handler handlerAnnotation;
    public EventHandler eventHandlerAnnotation;
    /** 当前方法参数对象 */
    public ParamInfo[] paramInfos;
    /** 返回的类型 */
    public Class<?> returnClazz;

    public RouteInfo() {
    }

    public static RouteInfo valueOf(BaseRoute instance, Class<?> clazz, Route routeAnnotation, Method method) {
        Rpc rpcAnnotation = method.getAnnotation(Rpc.class);
        Handler handlerAnnotation = method.getAnnotation(Handler.class);
        EventHandler eventHandler = method.getAnnotation(EventHandler.class);
        RouteInfo routeInfo = new RouteInfo();

        if (rpcAnnotation == null && handlerAnnotation == null && eventHandler == null) {
            return null;
        }
        var methodAccess = MethodAccess.get(clazz);
        // 方法名
        String methodName = method.getName();
        // 方法下标
        int methodIndex = methodAccess.getIndex(methodName);
        // 方法返回值类型
        Class<?> returnClazz = methodAccess.getReturnTypes()[methodIndex];
        routeInfo.returnClazz = returnClazz;

        // 方法参数
        Parameter[] parameters = method.getParameters();
        if (parameters != null && parameters.length > 0) {
            ParamInfo[] paramArr = new ParamInfo[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                paramArr[i] = new ParamInfo(i, parameters[i]);
            }
            routeInfo.paramInfos = paramArr;
        }

        routeInfo.instance = instance;
        routeInfo.instanceClazz = clazz;
        routeInfo.method = ASMMethod.valueOf(method, instance);
        routeInfo.routeAnnotation = routeAnnotation;

        if(rpcAnnotation != null) {
            routeInfo.rpcAnnotation = rpcAnnotation;
            routeInfo.routeName = routeInfo.buildRouteName(clazz, routeAnnotation, method, "");
        }

        if(handlerAnnotation != null) {
            routeInfo.handlerAnnotation = handlerAnnotation;
            routeInfo.routeName = routeInfo.buildRouteName(clazz, routeAnnotation, method, handlerAnnotation.cmd().cmdName);
        }
        if(eventHandler != null){
            routeInfo.eventHandlerAnnotation = eventHandler;
            routeInfo.routeName = routeInfo.buildRouteName(clazz, routeAnnotation, method, eventHandler.cmd().cmdName);
        }

        return routeInfo;
    }

    /**
     * 结点类型
     * @return
     */
    public ServiceEnum nodeType() {
        return this.routeAnnotation.serviceType();
    }

    public String buildRouteName(Class<?> clazz, Route annotationRoute, Method method, String methodName) {
        return String.join(".",
                nodeType().cmdName,
                StringUtils.isBlank(annotationRoute.name()) ? clazz.getSimpleName() : annotationRoute.name(),
                StringUtils.isBlank(methodName) ? method.getName() : methodName);
    }

    public Object invoke(Object... args) {
        return this.method.invoke(args);
    }
}
